package org.example.aienglishapp.controller.login;

import jakarta.validation.Valid;
import org.example.aienglishapp.annotation.debounce.Debounce;
import org.example.aienglishapp.annotation.operationlog.Loggable;
import org.example.aienglishapp.dto.login.CreateRoleRequestDTO;
import org.example.aienglishapp.dto.login.PermissionDTO;
import org.example.aienglishapp.dto.login.RoleDTO;
import org.example.aienglishapp.entity.login.Permission;
import org.example.aienglishapp.entity.login.Role;
import org.example.aienglishapp.mapper.login.PermissionMapper;
import org.example.aienglishapp.mapper.login.RoleMapper;
import org.example.aienglishapp.mapper.login.UserMapper;
import org.example.aienglishapp.service.login.PermissionService;
import org.example.aienglishapp.service.login.RoleService;
import org.example.aienglishapp.service.login.UserService;
import org.example.aienglishapp.util.response.ResponseResult;
import org.example.aienglishapp.util.response.ResultCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;

/**
 * @author xlj
 * @since 2024-10-1
 * @version 1.0
 */
@Slf4j
@RestController
@RequestMapping("/api/roles")
public class RoleController {

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private PermissionService permissionService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private RoleMapper roleMapper;

    /**
     * 创建角色。
     *
     * @param roleRequest 包含角色信息和权限ID集合的请求体
     * @return 创建成功或失败的响应结果
     */
    @Loggable("创建角色")
    @PostMapping()
    @Transactional
    public ResponseResult<Void> createRole(@Valid @RequestBody CreateRoleRequestDTO roleRequest) {
        log.info("接收到创建角色请求");

        // 检查角色名称是否已存在
        if (roleMapper.existsByRoleName(roleRequest.getRoleName())) {
            log.warn("创建角色失败：角色名称已存在，roleName={}", roleRequest.getRoleName());
            return ResponseResult.failed(ResultCode.CONFLICT.getCode(), "角色名称已存在");
        }

        // 检查角色ID是否已存在
        if (roleMapper.findById(roleRequest.getRoleId()) != null) {
            log.warn("创建角色失败：角色ID已存在，roleId={}", roleRequest.getRoleId());
            return ResponseResult.failed(ResultCode.CONFLICT.getCode(), "角色ID已存在");
        }

        // 创建角色实例
        Role newRole = new Role();
        newRole.setRoleId(roleRequest.getRoleId());
        newRole.setRoleName(roleRequest.getRoleName());

        // 处理 permissionIds 为 null 或空的情况
        Set<Permission> permissions;
        if (roleRequest.getPermissionIds() == null || roleRequest.getPermissionIds().isEmpty()) {
            log.info("权限ID集合为空，不设置权限");
            permissions = Set.of();
        } else {
            try {
                permissions = roleRequest.getPermissionIds().stream()
                        .distinct()
                        .map(permissionId -> {
                            Permission permission = permissionMapper.findById(permissionId);
                            if (permission == null) {
                                throw new IllegalArgumentException("权限ID不存在: " + permissionId);
                            }
                            log.info("查找并添加权限ID: {}", permissionId);
                            return permission;
                        })
                        .collect(Collectors.toSet());
            } catch (IllegalArgumentException e) {
                log.error("创建角色失败：{}", e.getMessage());
                return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), e.getMessage());
            }
        }
        newRole.setPermissions(permissions);

        // 保存角色
        log.info("即将保存的角色: {}", newRole);
        roleMapper.insert(newRole);

        // 插入角色权限关联
        for (Permission permission : newRole.getPermissions()) {
            log.info("即将插入role_permissions表的数据: 角色ID: {}, 权限ID: {}", newRole.getRoleId(), permission.getPermissionId());
            roleMapper.insertRolePermission(newRole.getRoleId(), permission.getPermissionId());
        }

        log.info("角色创建成功，roleId={}", newRole.getRoleId());

        return ResponseResult.success();
    }

    /**
     * 删除角色。
     *
     * @param roleId 角色的唯一标识符
     * @return 删除成功或失败的响应结果
     */
    @Loggable("删除角色")
    @DeleteMapping("/{roleId}")
    @Transactional
    public ResponseResult<Void> deleteRole(@PathVariable Long roleId) {
        // 检查角色是否存在
        if (!roleMapper.existsById(roleId)) {
            log.warn("删除角色失败：角色不存在，roleId={}", roleId);
            return ResponseResult.failed(ResultCode.NOT_FOUND.getCode(), "角色不存在");
        }

        // 检查角色是否有用户拥有
        if (userMapper.hasUsersWithRole(roleId)) {
            log.warn("删除角色失败：该角色有用户拥有，不能删除，roleId={}", roleId);
            return ResponseResult.failed(ResultCode.CONFLICT.getCode(), "该角色有用户拥有，不能删除");
        }

        // 删除角色权限关联
        roleMapper.deleteRolePermissions(roleId);

        // 安全删除角色
        roleMapper.deleteById(roleId);

        log.info("成功删除角色id {}", roleId);

        return ResponseResult.success();
    }

    /**
     * 获取所有权限。
     *
     * @return 包含所有权限信息的响应结果
     */
    @GetMapping("/permissions")
    public ResponseResult<List<PermissionDTO>> getAllPermissions() {
        try {
            List<PermissionDTO> permissions = permissionService.getAllPermissions();
            log.info("成功获取所有权限信息，数量为：{}", permissions.size());
            return ResponseResult.success(permissions);
        } catch (Exception e) {
            log.error("获取所有权限时出现异常：", e);
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "获取权限失败");
        }
    }

    /**
     * 更新角色信息。
     *
     * @param roleId 角色的唯一标识符
     * @param requestBody 包含新角色名称的请求体
     * @return 更新成功或失败的响应结果
     */
    @Loggable("更新角色名")
    @PutMapping("/{roleId}")
    @Transactional
    public ResponseResult<Void> updateRole(@PathVariable Long roleId, @RequestBody Map<String, Object> requestBody) {
        String newRoleName = (String) requestBody.get("roleName");

        // 检查新角色名称是否为空
        if (newRoleName == null || newRoleName.isEmpty()) {
            log.warn("更新角色失败：新角色名称不能为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "新角色名称不能为空");
        }

        // 检查角色是否存在
        Role role = roleMapper.findById(roleId);
        if (role == null) {
            log.warn("更新角色失败：角色不存在，roleId={}", roleId);
            return ResponseResult.failed(ResultCode.NOT_FOUND.getCode(), "角色不存在");
        }

        // 检查新角色名称是否已被使用
        if (roleMapper.existsByRoleName(newRoleName) && !role.getRoleName().equals(newRoleName)) {
            log.warn("更新角色失败：角色名称已存在，newRoleName={}", newRoleName);
            return ResponseResult.failed(ResultCode.CONFLICT.getCode(), "角色名称已存在");
        }

        // 更新角色名称
        role.setRoleName(newRoleName);
        roleMapper.updateRole(role);

        log.info("成功更新角色id {} 的名称为 {}", roleId, newRoleName);

        return ResponseResult.success();
    }

    /**
     * 获取所有角色及其权限接口。
     * 此接口用于获取系统中所有的角色信息及其关联的权限。
     *
     * @return 返回操作结果，包括成功或失败的状态码和消息
     */
    @GetMapping("/get-all-roles-with-permissions")
    public ResponseResult<List<RoleDTO>> getAllRolesWithPermissions() {
        log.info("接收到获取所有角色及其权限请求");

        try {
            List<RoleDTO> roles = roleService.getAllRolesWithPermissions();
            log.info("获取所有角色及其权限成功，角色数量: {}", roles.size());
            return ResponseResult.success(roles);
        } catch (Exception e) {
            log.error("获取所有角色及其权限过程中发生错误", e);
            // 如果发生异常，返回错误信息
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "获取所有角色及其权限失败，请重试或联系管理员。");
        }
    }

    /**
     * 为角色添加权限。
     *
     * @param roleId 角色的唯一标识符
     * @param request 包含权限ID的请求体
     * @return 添加成功后的响应结果
     */
    @Loggable("添加权限")
    @PostMapping("/{roleId}/permissions")
    @Debounce(interval = 500)
    public ResponseResult<Void> addPermissionToRole(@PathVariable Long roleId, @RequestBody Map<String, Long> request) {
        Long permissionId = request.get("permissionId");

        // 检查权限ID是否为空
        if (permissionId == null) {
            log.warn("添加权限失败：权限ID不能为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "权限ID不能为空");
        }

        // 检查角色ID是否为空
        if (roleId == null) {
            log.warn("添加权限失败：角色ID不能为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "角色ID不能为空");
        }

        try {
            permissionService.addPermissionToRole(roleId, permissionId);
            log.info("成功为角色id {} 添加权限id {}", roleId, permissionId);
            return ResponseResult.success();
        } catch (Exception e) {
            log.error("为角色添加权限失败：{}", e.getMessage());
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "添加权限失败，请稍后再试！");
        }
    }

    /**
     * 从角色中移除权限。
     *
     * @param roleId 角色的唯一标识符
     * @param permissionId 权限的唯一标识符
     * @return 移除成功后的响应结果
     */
    @Loggable("移除权限")
    @DeleteMapping("/{roleId}/permissions/{permissionId}")
    public ResponseResult<Void> removePermissionFromRole(@PathVariable Long roleId, @PathVariable Long permissionId) {
        // 检查角色ID和权限ID是否为空
        if (roleId == null || permissionId == null) {
            log.warn("移除权限失败：角色ID或权限ID不能为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "角色ID或权限ID不能为空");
        }

        try {
            permissionService.removePermissionFromRole(roleId, permissionId);
            log.info("成功从角色id {} 中移除权限id {}", roleId, permissionId);
            return ResponseResult.success();
        } catch (Exception e) {
            log.error("从角色移除权限失败：{}", e.getMessage());
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "移除权限失败，请稍后再试！");
        }
    }

    /**
     * 获取用户角色接口。
     * 此接口用于根据用户ID获取用户的角色信息。
     *
     * @param userId 用户ID
     * @return 返回操作结果，包括成功或失败的状态码和消息
     */
    @GetMapping("/{userId}/get-roles")
    public ResponseResult<List<RoleDTO>> getUserRoles(@PathVariable Long userId) {
        log.info("接收到获取用户角色请求, userId: {}", userId);

        try {
            List<RoleDTO> roles = userService.getUserRoles(userId);
            log.info("用户角色获取成功，userId: {}, 角色数量: {}", userId, roles.size());
            return ResponseResult.success(roles);
        } catch (Exception e) {
            log.error("获取用户角色过程中发生错误, userId: {}", userId, e);
            // 如果发生异常，返回错误信息
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "获取用户角色失败，请重试或联系管理员。");
        }
    }

    /**
     * 更新用户的角色。
     *
     * @param userId 用户的唯一标识符
     * @param requestBody 包含角色ID列表的请求体
     * @return 更新成功后的响应结果
     */
    @Loggable("更新用户角色")
    @PutMapping("/{userId}/update-roles")
    public ResponseResult<Void> updateUserRoles(@PathVariable Long userId, @RequestBody Map<String, Object> requestBody) {

        List<Integer> roleIds = null;
        try {
            roleIds = (List<Integer>) requestBody.get("roles");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        userService.updateUserRoles(userId, roleIds);
        return ResponseResult.success();
    }

    /**
     * 根据给定的权限ID列表获取指定权限及其关联的角色信息。
     *
     * @param permissionIds 权限ID列表
     * @return 包含权限及其关联角色信息的响应结果
     */
    @PostMapping("/get-permissions-with-roles")
    public ResponseResult<Map<String, Object>> getPermissionsWithRoles(@RequestBody List<Long> permissionIds) {
        if (permissionIds == null || permissionIds.isEmpty()) {
            log.warn("权限ID列表为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "权限ID不能为空");
        }

        try {
            Map<String, Object> data = permissionService.getPermissionsWithRoles(permissionIds);
            log.info("成功获取权限及其关联的角色信息");
            return ResponseResult.success(data);
        } catch (Exception e) {
            log.error("获取权限及其关联的角色信息时发生错误: {}", e.getMessage(), e);
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "获取权限信息失败: " + e.getMessage());
        }
    }

    /**
     * 为权限添加角色。
     *
     * @param request 包含权限ID和角色ID的请求体
     * @return 添加成功或失败的响应结果
     */
    @Loggable("添加角色")
    @PostMapping("/add-role")
    public ResponseResult<Void> addRoleToPermission(@RequestBody Map<String, Long> request) {
        Long permissionId = request.get("permissionId");
        Long roleId = request.get("roleId");

        // 检查权限ID和角色ID是否为空
        if (permissionId == null || roleId == null) {
            log.warn("添加角色失败：权限ID或角色ID不能为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "权限ID或角色ID不能为空");
        }

        boolean success = roleService.addRoleToPermission(permissionId, roleId);

        if (success) {
            log.info("成功为权限id {} 添加角色id {}", permissionId, roleId);
            return ResponseResult.success();
        } else {
            log.warn("添加角色失败：无法为权限id {} 添加角色id {}", permissionId, roleId);
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "添加角色失败，请检查权限ID和角色ID是否正确");
        }
    }

    /**
     * 从权限中移除角色。
     *
     * @param request 包含权限ID和角色ID的请求体
     * @return 移除成功或失败的响应结果
     */
    @Loggable("移除角色")
    @PostMapping("/remove-role")
    public ResponseResult<Void> removeRoleFromPermission(@RequestBody Map<String, Long> request) {
        Long permissionId = request.get("permissionId");
        Long roleId = request.get("roleId");

        // 检查权限ID和角色ID是否为空
        if (permissionId == null || roleId == null) {
            log.warn("移除角色失败：权限ID或角色ID为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "权限ID或角色ID不能为空");
        }

        boolean success = roleService.removeRoleFromPermission(permissionId, roleId);

        if (success) {
            log.info("成功从权限id {} 中移除角色id {}", permissionId, roleId);
            return ResponseResult.success();
        } else {
            log.warn("移除角色失败：无法从权限id {} 中移除角色id {}", permissionId, roleId);
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "移除角色失败，请检查权限ID和角色ID是否正确");
        }
    }
}

